/*
 * Copyright 2023-2023 the original author or authors.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      https://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
 */

package net.yun789.javasipweb.config;

import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import javax.sip.*;
import javax.sip.address.AddressFactory;
import javax.sip.header.HeaderFactory;
import javax.sip.message.MessageFactory;
import java.util.Properties;

@Configuration
@Slf4j
public class SipConfig {

    private volatile SipFactory sipFactory;

    private SipStack sipStack;

    /**
     * 内网ip地址
     */
    @Value("${address.internal}")
    private String addressInternal;
    /**
     *
     */
    @Value("${address.outernet}")
    private String addressOuternet;

    /**
     * 服务器侦听端口
     */
    @Value("${address.internal.port}")
    private int port = 9060;

    /**
     * sip工厂
     * @return
     */
    @Bean
    public SipFactory getSipFactory(){
        if(sipFactory==null){
            return  getSipFactoryInernal();
        }else {
            return sipFactory;
        }


    }

    /**
     * 单利模式
     * @return
     */
    private synchronized SipFactory getSipFactoryInernal(){
        if(this.sipFactory ==null){
            SipFactory  sipFactoryInernal = SipFactory.getInstance();
            sipFactoryInernal.setPathName("gov.nist");
            this.sipFactory=sipFactoryInernal;
        }
        return sipFactory;
    }

    /**
     *
     * @return
     */
    @Bean
    public synchronized SipStack getSipStack() throws PeerUnavailableException {
        if(sipStack==null){
            SipFactory sipFactory = this.getSipFactory();
            Properties properties = new Properties();
            properties.setProperty("javax.sip.STACK_NAME", "sipphone");
            // You need 16 for logging traces. 32 for debug + traces.
            // Your code will limp at 32 but it is best for debugging.
            properties.setProperty("gov.nist.javax.sip.TRACE_LEVEL", "16");
            properties.setProperty("gov.nist.javax.sip.DEBUG_LOG",
                    "javasipwebdebug.log");
            properties.setProperty("gov.nist.javax.sip.SERVER_LOG",
                    "javasipwebinfo.log");

            SipStack sipStack = sipFactory.createSipStack(properties);
            this.sipStack=sipStack;
        }
        return sipStack;
    }

    @Bean
    public HeaderFactory getHeaderFactory() throws PeerUnavailableException {
        SipFactory sipFactory = this.getSipFactory();
        return sipFactory.createHeaderFactory();
    }

    @Bean
    public AddressFactory getAddressFactory() throws PeerUnavailableException {
        SipFactory sipFactory = this.getSipFactory();
        return sipFactory.createAddressFactory();
    }

    @Bean
    public MessageFactory getMessageFactory() throws PeerUnavailableException {
        SipFactory sipFactory = this.getSipFactory();
        return sipFactory.createMessageFactory();
    }

    @Bean
    public SipProvider getSipProvider() throws ObjectInUseException, InvalidArgumentException, TransportNotSupportedException, PeerUnavailableException {
        SipStack sipStack = this.getSipStack();
        ListeningPoint lp = this.sipStack.createListeningPoint(addressInternal,
                port, "udp");
        log.info("addressInternal:{}",addressInternal);
        log.info("addressOuternet:{}",addressOuternet);
        log.info("port:{}",port);
        return this.sipStack.createSipProvider(lp);

    }



}
